<template>
  <div class="bigBox">
    <!-- <div class="topBtnBox">
      <button>我的作品</button>
    </div> -->
    <div class="main">
      <div class="leftBox" ref="leftBox">
        <seleModelStyles @openLoginFun="openLoginFun" @changeStyle="changeStyle" @changeSize="changeSize"
          @changeNum="changeNum" @changeUpImg="changeUpImg" :jsonData="{}" />
        <div class="leftItem">
          <p>关键词输入</p>
          <el-button class="promptBtn" :loading="optimizeFlag" @click="optimize">优化提示词</el-button>
          <el-input v-model="prompt" :rows="8" type="textarea" resize='none' placeholder="请输入您的提示词，支持中英文" />
        </div>

        <div class="leftItem">
          <p>反向提示词</p>
          <el-input v-model="negative_prompt" :rows="6" type="textarea" resize='none' placeholder="请输入您的反向提示词，支持中英文" />
        </div>
        <el-button class="paintBtn" @click="hdScale = 2; aiPaint(null)" :loading="paintIng">{{ '立即生成（-' + batch_size *
          pegg +
          '皮蛋）' }}</el-button><br>
        <!-- <el-button class="paintBtn" @click="hdScale = 4; aiPaint(null)" :loading="paintIng">{{ '高清生成（-' + batch_size *
          pegg
          * 2 + '皮蛋）' }}</el-button> -->
      </div>
      <div class="downTip" v-show="downFlag">
        <img :src="getPublic('image/向下.svg')" width="14" alt="" srcset="">
        <p>向下滑动</p>
      </div>

      <div class=" rightBox">
        <div style="max-width: 800px;margin: 0 auto;">
          <el-input placeholder="请输入您的标题，仅做保存历史使用" v-model="taskTitle"></el-input>
        </div>
        <div class="rightMain">
          <div class="imgsBox">
            <span v-for="(item, index) in paintImgsRes" :class="index == checkImg && !!item ? 'seleImgSpan' : ''"
              @click="!!item ? checkImg = index : ''">
              <el-image v-show="!!item" :src="item" fit="contain" :preview-src-list="paintImgsRes"
                :initial-index="index" />
              <el-image v-show="!item">
                <template #error>
                  <div class="image-slot">
                  </div>
                </template>
              </el-image>

              <!-- <el-image :src="item.base64"></el-image> -->
            </span>
          </div>
          <!-- <p v-show="!(progress == 0 || progress == 1)">{{ '生成进度：' + progress }}</p> -->
          <div class="imgsBtnBox">
            <!-- <button class="checkImg" @click="checkImg">查看大图</button> -->
            <el-button class="save" @click="download(false)" :loading="downlaodFlag">
              <img :src="getPublic('image/downloadBlue.png')" alt="">
              下载图片</el-button>
            <!-- <el-button class="download " id="plus" @click="download(true)" :loading="downlaodFlag">
              <img :src="getPublic('image/download.png')" alt="">
              高清下载(限免)</el-button> -->
            <!-- <el-button class="save">
              <img :src="getPublic('image/shoucang.png')" alt="">
              保存历史</el-button> -->
            <el-popconfirm title="即将生成相似，本次结果已保存到作品历史，是否继续?" @confirm="rePaint" width="300">
              <template #reference>
                <el-button class="rePaint">{{ '生成相似(-' + batch_size * pegg + '皮蛋)' }}</el-button>
                <!-- <el-button>Delete</el-button> -->
              </template>
            </el-popconfirm>
            <!-- <el-button class="rePaint">生成相似</el-button> -->
          </div>
          <div v-if="paintIng" class="progressDiv">
            <p>生成进度：</p>
            <span>
              <el-progress :color="'#77BF7B'" :duration="5" :percentage="progress * 100" :stroke-width="20" striped
                striped-flow />
            </span>

          </div>
        </div>

      </div>
      <div style="position: fixed;right: 30px;bottom: 100px;">
        <el-popover placement="left" title="关注公众号发送消息“画境”进群，领50皮蛋" :teleported="true" :width="400"
          popper-style="text-align: center;paddingTop:20px">
          <template #reference>
            <div class="qunBtn">
              <img :src="getPublic('image/erweima.png')" alt="">
              <p>欢迎进群</p>
            </div>
          </template>
          <el-image style="width: 380px;" src="http://arts.pencil-stub.com/qun.jpg" />
        </el-popover>
      </div>

    </div>

    <!-- 查看大图 -->
  </div>
</template>
<script setup lang="ts">
import {
  ref,
  reactive,
  getCurrentInstance,
  onMounted,
  toRefs,
  toRaw,
  onUnmounted,
  watch,
} from "vue";
import { useRouter } from "vue-router";
import { getPublic } from "../../request/getPublic"; //获取静态资源
import $apiFun from "../../request/api";
import { ElMessage } from 'element-plus'
import seleModelStyles from "../components/seleModelStyles.vue";
import { Picture as IconPicture } from '@element-plus/icons-vue'
import axios from "axios";
import { getUid } from "../../hooks/auth";
//定义要发送的emit事件
const emit = defineEmits(['openLogin'])
const leftBox = ref<HTMLDivElement | null>(null);//左侧dom元素
const prompt = ref('')//正向提示词
const negative_prompt = ref('')//正向提示词
const downlaodFlag = ref(false)//下载等待load
const pegg = ref(4); //绘图单价--皮蛋数
const seleStyle = ref({
  preset_info: {
    prompt: '',
    negative_prompt: ''
  },
  model_class: 0
}) as any//选择的风格
const taskTitle = ref('')//任务标题
const batch_size = ref(1)//生成数量
const sizeData = ref([])//生成尺寸
const optimizeFlag = ref(false)//优化提示词按钮加载flag

const uids = [10001189, 10209460, 10148737]//不走鉴黄的账号
const paintImgsRes = ref([
  "", "", "", ""
]) as any//图片数组
const checkImg = ref(0)//选择的图片
const paintIng = ref(false)//绘画中load
const progress = ref(0)//任务进度显示
const hdScale = ref(2)//放大倍数
const downFlag = ref(true)
//打开登录页
const openLoginFun = () => {
  emit('openLogin', true)
}
const image = ref('') as any//参考图地址

//更改风格
const changeStyle = (data: any) => {
  seleStyle.value = data
  if (typeof data.preset_info == 'string') seleStyle.value.preset_info = JSON.parse(data.preset_info);
  //应用正向词和负向词
  // if (prompt.value.length > 0) {
  //   prompt.value = seleStyle.value.preset_info.prompt + '' + prompt.value
  // } else {
  //   prompt.value = seleStyle.value.preset_info.prompt
  // }
  console.log(seleStyle.value.preset_info)
  prompt.value = seleStyle.value.preset_info.prompt
  negative_prompt.value = seleStyle.value.preset_info.negative_prompt
}
//上传图生图的参考图
const changeUpImg = async (data: string) => {
  console.log('上传图生图的参考图', data)
  if (data) {
    let inputImg = await imgToBase64(data, true)
    image.value = inputImg
  } else {
    image.value = ""
  }

}
//更改数量
const changeNum = (data: any) => {
  //超过4张打折
  if (data > 4) {
    pegg.value = 2
  } else {
    pegg.value = 4
  }
  if (data >= 10) {
    ElMessage.info("当前任务超过10张，请注意皮蛋消耗")
  }
  batch_size.value = data
}
//更改尺寸
const changeSize = (data: any) => {
  sizeData.value = data
}
//优化提示词
const optimize = () => {
  if (!prompt.value) {
    ElMessage.error("请先输入您的提示词")
    return
  }
  optimizeFlag.value = true
  let p = {
    spec: {
      prompt: prompt.value,
      temperature: 0.1//0.1-1越大，Ai发挥更高想象力
    }
  }
  $apiFun.optimize(p).then((res: any) => {
    console.log(res)
    optimizeFlag.value = false
    if (res.code == 200) {
      try {
        prompt.value = JSON.parse(res.data.prompt).en
      } catch (error) {

      }
    }
  })
}
//生成相似
const rePaint = () => {
  if (!paintImgsRes.value[checkImg.value]) {
    ElMessage.error("请选择一个图片")
    return
  }
  aiPaint(paintImgsRes.value[checkImg.value])
}
//请求绘画
const aiPaint = async (rePaintImg: string | null) => {
  if (prompt.value.length == 0) {
    ElMessage.error("请输入关键词后再访问")
    return
  }
  paintIng.value = true
  //组装请求数据
  let req = {
    pegg: pegg.value * 10 * batch_size.value * hdScale.value / 2,
    type: 2,
    style_id: seleStyle.value.id,
    //存储信息，复制时需要使用
    req_json: {
      num: batch_size.value,
      // negative_prompt: jsonData.negative_prompt,
      img_size: sizeData.value[2]
    },
    spec: {
      scenes: await matePrompt(prompt.value),
      title: taskTitle.value.length > 0 ? taskTitle.value : prompt.value,
      icon: seleStyle.value.icon,
      detection: uids.indexOf(getUid()) != -1 ? false : true, //是否鉴黄
      model: 1.4,
      ai_paint: {
        negative_prompt: negative_prompt.value,
        model: seleStyle.value.model_class,
        width: sizeData.value[0],
        height: sizeData.value[1],
        batch_size: 1,
        steps: seleStyle.value.preset_info.steps || 20,
        cfg_scale: seleStyle.value.preset_info.cfg_scale || 7,
        style_name: seleStyle.value.preset_info.style_name,
        sampling: seleStyle.value.preset_info.sampling,
        lora: seleStyle.value.preset_info.lora,
        seed: -1
      },
      hd: {
        scale: hdScale.value,
        strength: seleStyle.value.preset_info?.hd?.strength || 0.6,
        model_type: seleStyle.value.preset_info?.hd?.model_type || 0
      }
    },
  } as any
  //如果传了参考图，需要将原图尺寸放大，去除hd参数
  if (image.value.length != 0) {
    req.spec.ai_paint.image = image.value
    req.spec.ai_paint.strength = 0.5//越小越相似0.1-0.5
    //   req.spec.ai_paint.width = sizeData.value[0] * 2
    //   req.spec.ai_paint.height = sizeData.value[1] * 2
    //   delete req.spec.hd
  }
  //如果是重绘。则单次增加参考图
  if (!!rePaintImg) {
    console.log("是重绘")
    req.spec.ai_paint.image = rePaintImg
    req.spec.ai_paint.strength = 0.5//越小越相似0.1-0.5
    // req.spec.ai_paint.width = sizeData.value[0] * 2
    // req.spec.ai_paint.height = sizeData.value[1] * 2
    // delete req.spec.hd
  }

  $apiFun.addScriptTask(req).then((res: any) => {
    console.log('addScriptTask', res)
    if (res.code == 1001) {
      openLoginFun
      paintIng.value = false
      return
    }
    if (res.code == 200) {
      //超过4张提示去历史记录
      if (batch_size.value > 4) {
        ElMessage.success("您的图片数量超过4张，请前往历史记录中查看本次绘图任务")
        paintIng.value = false
      } else {
        //没超过4张，在页面中等待进度
        timeGetTaskProgress(res.data.task_id)
      }
    } else {
      paintIng.value = false
      ElMessage.warning(res.msg)
    }
  });
}
let taskTime = 0 as any
//2s轮询任务进度
const timeGetTaskProgress = async (task_id: string) => {
  //清除轮询任务列表定时器
  clearTimer();
  //查询任务
  await getTaskProgtess(task_id)
  if (progress.value != 1) {
    taskTime = setTimeout(() => {
      timeGetTaskProgress(task_id);
    }, 2000);
  } else {
    paintIng.value = false
    getTaskInfo(task_id)
    console.log("已经完成任务了", task_id)
  }
};
//发起请求任务进度
const getTaskProgtess = async (task_id: string) => {
  await $apiFun.ScriptProgress({ task_id: task_id }).then((res: any) => {
    console.log('ScriptProgress', task_id, res)
    if (res.code == 200) {
      progress.value = res.data.progress
    }
  })
  return
}
//获取任务详情
const getTaskInfo = async (task_id: string) => {
  await $apiFun.ScriptTaskInfo({ spec: { task_id: task_id } }).then(async (res: any) => {
    if (res.code == 200) {
      let data = res.data
      let resUrl = [] as any
      data.scenes[0].imgs.forEach(element => {
        resUrl.push(element.url)
      });
      formatImg(resUrl)
      changeStatus(task_id, 3)
    }
    console.log("获取任务详情", res);
  });
}
//更新任务状态
const changeStatus = (task_id: string, status: number) => {
  $apiFun.upTaskStatus({ spec: { status_0: status, task_id: task_id } }).then((res: any) => {
    console.log('changeStatus', res)
  })
}
//将json数据格式化为base64图
const formatImg = async (imgList: any) => {
  //存储加载任务promise
  let primary = [] as any
  paintImgsRes.value = ['', '', '', '']
  imgList.forEach((element: any, index: number) => {
    const taskInfo = new Promise((resolve) => {
      if (element.substring(element.length - 5) == '.json') {
        //服务器返回json文件
        axios({
          method: 'get',
          url: window.location.host.indexOf('pencil-stub.com') != -1 ? element : '/file-pencil' + element.substring(element.indexOf('/data/AiPaint')),
          responseType: 'json'
        }).then(response => {
          paintImgsRes.value[index] = 'data:image/jprg;base64,' + response.data.substring(response.data.indexOf('/'), response.data.indexOf(', url='))
          resolve("ok")
          // 进行进一步操作，如保存文件或处理文件内容
        })
      } else {
        //服务器返回其他格式文件
        axios.get(window.location.host.indexOf('pencil-stub.com') != -1 ? element : '/file-pencil' + element.substring(element.indexOf('/data/aiPaint')), { responseType: 'blob' })
          .then(response => {
            const reader = new FileReader();
            reader.onloadend = () => {
              const base64 = reader.result;
              paintImgsRes.value[index] = base64
              resolve("ok")
            };
            reader.readAsDataURL(response.data);
          })
      }
    })
    primary.push(taskInfo)

  });
  //  全部图片加载完成
  await Promise.all(primary).then(() => {
  })
}
//清除轮询任务列表定时器
const clearTimer = () => {
  clearTimeout(taskTime);
  taskTime = 0;
};
//组装提示词
const matePrompt = async (text: string) => {
  let scenes = [[]] as any;
  const pattern = /[\u4e00-\u9fa5]/; // 使用Unicode范围匹配中文字符
  if (pattern.test(text)) {
    text = await fanyi(text)
  }
  for (let i = 0; i < batch_size.value; i++) {
    scenes[0].push({ sentence: text, desc: text, roles: [] });
  }
  return scenes;
};
//翻译
const fanyi = async (text: string) => {
  let dst = ""
  try {
    await $apiFun.Fanyi({ q: text, to: "en" }).then(async (res: any) => {
      dst = res.trans_result[0].dst
    })
  } catch (error) {
    let req = {
      spec: {
        fromContent: text,
        lanTo: "en"
      }
    }
    await $apiFun.FanyiPP(req).then((res: any) => {
      dst = res.data.content
    })
  }
  console.log(dst)
  return dst
}
//将图片链接转为base64
const imgToBase64 = async (data: string, flag: boolean | null) => {
  return new Promise<string>((resolve, reject) => {
    let url = '';
    let base64: any;
    if (flag || window.location.host.indexOf('pencil-stub.com') != -1) {
      url = data;
    } else {
      url = '/file-pencil' + data.substring(data.indexOf('/data/aiPaint'));
    }
    axios.get(url, { responseType: 'blob' })
      .then(response => {
        const reader = new FileReader();
        reader.onloadend = () => {
          base64 = reader.result;
          resolve(base64);
        };
        reader.readAsDataURL(response.data);
      })
      .catch(error => {
        reject(error);
      });
  });
};

//下载图片
const download = async (hdFlag: any) => {
  if (!!paintImgsRes.value[checkImg.value]) {
    downlaodFlag.value = true
    let resImg = paintImgsRes.value[checkImg.value]
    if (hdFlag) {
      let p = {
        spec: {
          image: resImg,
          upscaling_resize: 2,
          type: 1
        }
      }
      //发起高清处理请求
      await $apiFun.hdImg(p).then(async (res: any) => {
        if (res.code == 200) {
          resImg = res.data.image
        }
      })
    }
    // console.log(resImg)
    // 创建一个虚拟的a标签
    const link = document.createElement('a');
    link.href = resImg.indexOf('base64,') == -1 ? 'data:image/jpeg;base64,' + resImg : resImg;
    link.download = "画境Ai绘画" + Math.floor(Math.random() * (999999 - 100000 + 1)) + '.jpg';
    // 模拟点击下载链接
    link.click();
    downlaodFlag.value = false
  } else {
    ElMessage.error("请选择一个图片")
  }
}
//获取时间戳
const getTimeLabel = () => {
  const now = new Date();
  const hours = String(now.getHours()).padStart(2, '0');     // 小时（在小于10的数字前补零）
  const minutes = String(now.getMinutes()).padStart(2, '0'); // 分钟（在小于10的数字前补零）
  const seconds = String(now.getSeconds()).padStart(2, '0'); // 秒钟（在小于10的数字前补零）
  return `${hours}:${minutes}:${seconds}`;
}
//滚动监测
const changeScroll = (event: Event) => {
  const container = event.target as HTMLDivElement;
  if (container.scrollHeight - container.clientHeight - container.scrollTop <= 10) {
    downFlag.value = false
  } else {
    downFlag.value = true
  }
}
// 页面销毁，去除查询服务器状态定时器
onUnmounted(() => {
  console.log('钩子销毁，移除定时器')
  clearTimer()
  leftBox.value?.removeEventListener('scroll', changeScroll)
})
onMounted(() => {
  leftBox.value?.addEventListener('scroll', changeScroll);
  // setTimeout(() => {
  //   emit('openLogin', true)
  //   console.log(123)
  // }, 2000);
});
</script>

<!-- 右边预览 -->
<style scoped>
.progressDiv p {
  width: 80px;
  display: inline-block;
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  left: 0;
}

.progressDiv span {
  display: inline-block;
  width: calc(100% - 80px);
  position: absolute;
  top: 50%;
  right: 0;
  transform: translateY(-50%);
}

.progressDiv {
  position: relative;
  width: 100%;
  height: 80px;
  vertical-align: middle;
  /* background-color: red; */
}

:deep(.qunBtn img) {
  width: 66px;
  margin: 5px 0 6px 0;
}

:deep(.qunBtn) {
  width: 77px;
  height: 104px;
  opacity: 1;
  border-radius: 10px;
  background: rgba(255, 255, 255, 0.5);
  box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.25);
  text-align: center;
  font-size: 12px;
  color: rgba(0, 0, 0, 1);

}

.rePaint,
:deep(.imgsBtnBox .rePaint):focus,
.rePaint:hover,
.el-button:active {
  background: rgba(56, 56, 56, 1);
  border: 1px solid rgba(0, 0, 0, 1);
  color: rgba(255, 255, 255, 1);
}

.imgsBtnBox .save,
:deep(.imgsBtnBox .save):focus {
  display: inline-block;
  background: rgba(42, 130, 228, 1);
  border: 1px solid rgba(140, 194, 255, 1);
  color: rgba(255, 255, 255, 1);
  padding: 0;
}

:deep(.el-button):focus {
  color: initial;
  background-color: initial;
  border: initial;
}

#plus {
  background: rgba(255, 195, 0, 1);
  border: 1px solid rgba(255, 235, 59, 1);
  color: rgba(255, 255, 255, 1);
}

.imgsBtnBox .download {
  display: inline-block;
  background: rgba(255, 255, 255, 1);
  border: 1px solid rgba(166, 166, 166, 1);
  color: rgba(128, 128, 128, 1);
  padding: 0;
}

.checkImg {
  color: rgba(128, 128, 128, 1);
  background: rgba(255, 255, 255, 1);
  border: 1px solid rgba(166, 166, 166, 1);
}

.imgsBtnBox img {
  width: 12px;
  vertical-align: middle;
  /* margin-bottom: 2px; */
  margin: 6px;
  margin-left: -4px;
}

.imgsBtnBox button {
  width: 33%;
  height: 35px;
  border-radius: 5px;
  font-size: 12px;
  cursor: pointer;
}

.imgsBtnBox {
  vertical-align: middle;
  display: flex;
  justify-content: space-around;
  margin-top: 20px;
}

:deep(.imgsBox span .el-image) {
  width: 100%;
  height: 100%;
}

.imgsBox span img {
  width: 100%;
  aspect-ratio: 1/1;
}

.imgsBox span {
  display: inline-block;
  width: 50%;
  height: 50%;
  aspect-ratio: 1/1;
  box-sizing: border-box;
  border: 2px solid #fff;
  vertical-align: top;
}

.imgsBox .seleImgSpan {
  border-color: rgba(255, 195, 0, 1);

}

.imgsBox {
  max-width: 100%;
  max-height: 100%;
  aspect-ratio: 1/1;
  background-color: rgba(229, 229, 229, 1);
  margin: 0 auto;
}

.rightMain {
  width: 100%;
  max-width: 800px;
  height: 100%;
  margin: 0 auto;
}

.rightBox {
  position: absolute;
  width: 50%;
  height: 80%;
  right: 0;
  top: 30px;
  padding: 0 40px;
  box-sizing: border-box;
}
</style>
<!-- 中间和左边 -->
<style scoped>
.downTip {
  width: 100%;
  position: absolute;
  bottom: -30px;
  width: 50%;
  text-align: center;
  font-size: 10px;
  color: #707070;
}

.paintBtn {
  width: 100%;
  height: 40px;
  opacity: 1;
  border-radius: 20px;
  margin-top: 20px;
  background: rgba(56, 56, 56, 1);
  border: 0px;
  /** 文本1 */
  font-size: 12px;
  color: rgba(255, 255, 255, 1);

}

:deep(.leftItem .promptBtn) {
  position: absolute;
}

:deep(.leftItem .promptBtn):hover,
:deep(.leftItem .promptBtn):active,
:deep(.leftItem .promptBtn):focus {
  border: 0px;
  color: rgba(0, 0, 0, 1);
  background: rgba(255, 226, 41, 1);
}

.promptBtn {
  cursor: pointer;
  position: absolute;
  right: 0;
  top: 0;
  margin-top: 10px;
  border: 0px;
  width: 88px;
  height: 30px;
  border-radius: 15px;
  background: rgba(255, 226, 41, 1);
  font-size: 12px;
  font-weight: 400;
  letter-spacing: 0px;
  color: rgba(0, 0, 0, 1);
}

.leftItem p {
  font-size: 16px;
  font-weight: 500;
  line-height: 23.17px;
  color: rgba(0, 0, 0, 1);
  margin: 10px 0;
}

.leftItem {
  position: relative;
  padding: 10px 0;
}

.leftBox {
  position: absolute;
  width: 50%;
  left: 0;
  height: 100%;
  overflow-y: auto;
}

.leftBox::-webkit-scrollbar {
  display: none;
  /* 隐藏滚动条 */
}


.main {
  width: 100%;
  height: calc(100% - 50px);
  position: relative;
}
</style>
<!-- 全局和顶部 -->
<style scoped>
.topBtnBox button {
  width: 166px;
  height: 39px;
  opacity: 1;
  border-radius: 28.45px;
  background: rgba(255, 226, 41, 1);
  box-shadow: 0px 3px 22px rgba(255, 195, 0, 0.41);
  border: 0px solid rgba(255, 226, 41, 1);
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

.topBtnBox {
  position: relative;
  width: 182px;
  height: 50px;
  opacity: 1;
  border-radius: 35px;
  background: rgba(255, 195, 0, 0.07);
  border: 0.3px solid rgba(255, 226, 41, 1);
  box-shadow: 0px 0px 3px rgba(255, 195, 0, 0.3);
  backdrop-filter: blur(6px);
}

.bigBox {
  width: 100%;
  height: 100%;
  padding: 25px 0 0 30px;
  padding-bottom: 50px;
  box-sizing: border-box;
}
</style>
